package com.yyw.gulimall.member.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yyw.common.enums.common.OAuth2SourceEnum;
import com.yyw.common.exception.OAuth2LoginException;
import com.yyw.common.exception.UserLoginException;
import com.yyw.common.exception.UserRegisterException;
import com.yyw.common.utils.PageUtils;
import com.yyw.common.utils.Query;
import com.yyw.common.utils.enums.ExceptionEnum;
import com.yyw.gulimall.member.abstracts.RootOAuth2Service;
import com.yyw.gulimall.member.dao.MemberDao;
import com.yyw.gulimall.member.entity.MemberEntity;
import com.yyw.gulimall.member.entity.MemberLevelEntity;
import com.yyw.gulimall.member.entity.MemberOauth2Entity;
import com.yyw.gulimall.member.service.MemberLevelService;
import com.yyw.gulimall.member.service.MemberOauth2Service;
import com.yyw.gulimall.member.service.MemberService;
import com.yyw.gulimall.member.utils.SpringUtil;
import com.yyw.gulimall.member.vo.LoginUserVo;
import com.yyw.common.to.oauth.MemberVo;
import com.yyw.gulimall.member.vo.weibo.AccessTokenResult;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;
import java.util.Objects;


@Service("memberService")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    private final MemberLevelService memberLevelService;

    private final MemberOauth2Service memberOauth2Service;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<MemberEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public void registerUser(MemberEntity member) {
        // 1. 判断手机号和用户名是否存在
        if (!checkPhoneOrUserNameExist(member, "mobile")) {
            throw new UserRegisterException(ExceptionEnum.USER_BIND_RESULT_PHONE.getMsg());
        }
        if (!checkPhoneOrUserNameExist(member, "username")) {
            throw new UserRegisterException(ExceptionEnum.USER_BIND_RESULT_USERNAME.getMsg());
        }

        // 2. 密码加密
        String password = member.getPassword();
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String newPassWord = passwordEncoder.encode(password);
        member.setPassword(newPassWord);

        // 3. 查询默认等级
        MemberLevelEntity levelEntity = memberLevelService.getOne(new QueryWrapper<MemberLevelEntity>()
                .lambda().eq(MemberLevelEntity::getDefaultStatus, 1));
        member.setLevelId(Objects.equals(null, levelEntity) ? -1 : levelEntity.getId());

        // 4. 设置默认设置
        member.setStatus(1);
        member.setCreateTime(new Date());
        // 5. 保存
        this.save(member);
    }

    /**
     * 用户登录
     *
     * @param userVo
     * @return
     */
    @Override
    public MemberVo loginUser(LoginUserVo userVo) {
        boolean flag = true;
        // 根据用户名或者手机号查询用户
        QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MemberEntity::getMobile, userVo.getUsername()).or().eq(MemberEntity::getUsername, userVo.getUsername());
        MemberEntity entity = this.getOne(queryWrapper);
        if (Objects.isNull(entity)) {
            // 用户不存在
            throw new UserLoginException(ExceptionEnum.USER_LOGIN_EXCEPTION.getMsg());
        }
        // 密码校验
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(userVo.getPassword(), entity.getPassword())) {
            // 密码错误
            throw new UserLoginException(ExceptionEnum.USER_LOGIN_EXCEPTION.getMsg());
        }
        MemberVo vo = new MemberVo();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }

    /**
     * 第三方认证服务
     *
     * @param tokenResult 请求的数据
     * @param source      来源: QQ/微博
     * @return
     */
    @Transactional
    @Override
    public MemberVo oauthLoginOrRegister(AccessTokenResult tokenResult, String source) {
        MemberOauth2Entity oauth2Entity = null;
        MemberEntity member = null;
        RootOAuth2Service oAuth2Service = null;
        // 判断来源，封装数据
        if (source.equalsIgnoreCase(OAuth2SourceEnum.OAUTH2_WEIBO.getName())) {
            oAuth2Service = SpringUtil.getBean(WeiboOAuth2ServiceImpl.class);
            oauth2Entity = oAuth2Service.packageData(tokenResult);
        }

        // 如果来源不正确就抛出异常
        if (Objects.equals(null, oauth2Entity)) {
            throw new OAuth2LoginException("第三方认证：没有找到相关的实现类");
        }

        // 查询关联关系
        MemberOauth2Entity oauth2 = oAuth2Service.getInfoBySource(oauth2Entity);

        if (Objects.equals(null, oauth2)) {
            // 不存在，第一次登录，注册用户
            member = oAuth2Service.packageDataByMember(tokenResult);
            this.save(member);
            // 保存第三方关联表
            oauth2Entity.setMemberId(member.getId());
            memberOauth2Service.save(oauth2Entity);
        } else {
            // 之前登录过，如果token不一样，则更新token和过期时间
            if (!Objects.equals(tokenResult.getAccess_token(),oauth2.getAccessToken())) {
                oauth2Entity.setId(oauth2.getId());
                memberOauth2Service.updateById(oauth2Entity);
            }
            // 查询会员表，返回
            member = this.getById(oauth2.getMemberId());
        }
        MemberVo memberVo = new MemberVo();
        BeanUtils.copyProperties(member, memberVo);
        return memberVo;
    }

    /**
     * 检验用户名或手机号是否存在
     *
     * @param member
     * @param key
     * @return
     */
    private boolean checkPhoneOrUserNameExist(MemberEntity member, String key) {
        QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
        if (key.equals("username")) {
            queryWrapper.eq(key, member.getUsername());
        } else {
            queryWrapper.eq(key, member.getMobile());
        }
        MemberEntity entity = this.getOne(queryWrapper);
        if (Objects.equals(null, entity)) {
            return true;
        }
        return false;
    }

}